package com.ruoyi.yuyuan.Service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.yuyuan.DTO.FollowDTO;
import com.ruoyi.yuyuan.DTO.FollowerDTO;
import com.ruoyi.yuyuan.DTO.Result;
import com.ruoyi.yuyuan.Entity.Event;
import com.ruoyi.yuyuan.Entity.Follow;
import com.ruoyi.yuyuan.Entity.Notice;
import com.ruoyi.yuyuan.Entity.User;
import com.ruoyi.yuyuan.Event.EventProducer;
import com.ruoyi.yuyuan.Mapper.FollowMapper;
import com.ruoyi.yuyuan.Mapper.UserMapper;
import com.ruoyi.yuyuan.Service.IFollowService;
import com.ruoyi.yuyuan.Utils.IdGenerator;
import com.ruoyi.yuyuan.Utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.ruoyi.yuyuan.Utils.CommunityConstant.ENTITY_TYPE_LIKE;
import static com.ruoyi.yuyuan.Utils.CommunityConstant.TOPIC_LIKE;
import static com.ruoyi.yuyuan.Utils.RedisConstants.FOLLOWS_KEY;
import static com.ruoyi.yuyuan.Utils.RedisConstants.FOLLOWS_LOCK;

/**
 * @Author: kestrel
 * @Version:1.0
 * @Date: 2024/5/29
 */
@Slf4j
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private FollowMapper followMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private EventProducer eventProducer;

    @Override
    public Result follow(Long followUserId) {
        Long userId = UserHolder.getUser().getId();
        //关注自己
        if (followUserId.equals(userId)) return Result.ok();
        //分布式锁操作
        Boolean isSuccess = stringRedisTemplate.opsForValue().setIfAbsent(FOLLOWS_LOCK + userId, "");
        boolean isFollow = followOrNot(followUserId);

        if (Boolean.FALSE.equals(isSuccess)) {
            return Result.fail("请勿频繁操作！");
        }
        //未关注
        if (!isFollow) {
            User user = userMapper.selectById(followUserId);
            if (user == null) {
                return Result.fail("用户不存在!");
            }
            String icon = user.getIcon();
            //创建对象
            Follow follow = new Follow(idGenerator.nextFollowId(), userId, followUserId, icon, LocalDateTime.now());
            //MySQL操作
            followMapper.insert(follow);
            stringRedisTemplate.expire(FOLLOWS_LOCK + userId, 10L, TimeUnit.SECONDS);
            //MySQL操作
            userMapper.addFollowee(userId);    //当前用户关注+1
            userMapper.addFans(followUserId);  //被关注者粉丝+1
            //Redis操作
            stringRedisTemplate.opsForSet().add(FOLLOWS_KEY + userId.toString(), followUserId.toString());

            // 触发关注通知事件
            String name = userMapper.selectById(userId).getName();
            Notice notice = new Notice(idGenerator.nextNoticeId(),0L,userId,followUserId,LocalDateTime.now(),
                    "comment","用户" + name + "关注了你");
            Event event = new Event(
                    TOPIC_LIKE,
                    UserHolder.getUser().getId(),
                    ENTITY_TYPE_LIKE,
                    0L,
                    notice,
                    "Notice");
            eventProducer.fireEvent(event);
        }
        //已关注
        else {
            //MySQL操作
            followMapper.deleteByUserIdAndFollowId(userId, followUserId);
            stringRedisTemplate.expire(FOLLOWS_LOCK + userId, 10L, TimeUnit.SECONDS);
            //MySQL操作
            userMapper.subFollowee(userId);    //当前用户关注-1
            userMapper.subFans(followUserId);  //被关注者粉丝-1
            //Redis操作
            stringRedisTemplate.opsForSet().remove(FOLLOWS_KEY + userId.toString(), followUserId.toString());
        }
        //释放锁
        stringRedisTemplate.delete(FOLLOWS_LOCK + userId);
        return Result.ok(!isFollow);
    }

    @Override
    public Result isFollow(Long tarId) {
        Long userId = UserHolder.getUser().getId();
        if (followMapper.isFollow(userId, tarId) == null) {
            return Result.ok(false);
        }
        return Result.ok(true);
    }

    @Override
    public Result myFollows() {
        return tarFollows(UserHolder.getUser().getId());
    }

    @Override
    public Result myFollowers() {
        return tarFollowers(UserHolder.getUser().getId());
    }

    /**
     * 查询目标用户的所有关注
     *
     * @param userId 目标用户id
     * @return 结果数据
     */
    @Override
    public Result tarFollows(Long userId) {
        //查询数据库
        List<Follow> follows = followMapper.getTarFollowsByUserId(userId);
        List<FollowDTO> result = new ArrayList<>();
        for (Follow follow : follows) {
            //复制属性
            FollowDTO followDTO = BeanUtil.copyProperties(follow, FollowDTO.class);
            User followUser = userMapper.selectById(followDTO.getFollowUserId());
            //设置属性
            followDTO.setFollowUserSex(followUser.getSex());
            followDTO.setFollowUserName(followUser.getName());
            //加入列表
            result.add(followDTO);
        }
        //处理头像临时链接
        for (FollowDTO follow : result) {
            follow.handlerImgs();
        }
        //返回结果
        return Result.ok(result, ((Integer) result.size()).longValue());
    }

    /**
     * 获取目标用户的粉丝
     *
     * @param userId 目标用户id
     * @return 结果数据
     */
    @Override
    public Result tarFollowers(Long userId) {
        //查询数据库
        List<Follow> followers = followMapper.getTarFollowersByUserId(userId);
        List<FollowerDTO> result = new ArrayList<>();
        for (Follow follow : followers) {
            //复制属性
            FollowerDTO followerDTO = BeanUtil.copyProperties(follow, FollowerDTO.class);
            User followUser = userMapper.selectById(followerDTO.getUserId());
            //设置属性
            followerDTO.setFollowerUserIcon(followUser.getIcon());
            followerDTO.setFollowerUserSex(followUser.getSex());
            followerDTO.setFollowerUserName(followUser.getName());
            //加入列表
            result.add(followerDTO);
        }
        //处理头像临时链接
        for (FollowerDTO follow : result) {
            follow.handlerImgs();
        }
        //返回结果
        return Result.ok(result, ((Integer) result.size()).longValue());
    }

    public boolean followOrNot(Long tarId) {
        Long userId = UserHolder.getUser().getId();
        return followMapper.isFollow(userId, tarId) != null;
    }
}
